package com.yunzan.sync_netty.server;


import com.yunzan.sync_netty.cache.ChannelMap;
import com.yunzan.sync_netty.model.Result;
import com.yunzan.sync_netty.model.Tenant;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: NettyServerHandler
 * @Author: huangzf
 * @Date: 2018/9/25 15:44
 * @Description:
 */
@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler {

    private CountDownLatch latch;
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss,yyyy-MM-dd");

    /**
     * 消息的唯一ID
     */
    private String unidId = "";
    /**
     * 同步标志
     */
    private int rec;
    /**
     * 客户端返回的结果
     */
    private Result result;
    /**
     * 心跳丢失次数
     */
    private int counter = 0;
    /**
     * 传送的指令
     */
    private String cmd;


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("Client say : " + msg.toString()+"  "+new Date());
        if (heartActive(ctx, (String) msg.toString())) { // 当时心跳信息自动回复
            return;
        }
        counter = 0;
        String text = msg.toString();
        if (rec == 1 && null != cmd && text.contains(cmd)) {
            Result re = new Result();
            re.setCode(0);
            re.setUniId(unidId);
            re.setMessage(text);
            //校验返回的信息是否是同一个信息
            if (unidId.equals(re.getUniId())) {
                latch.countDown();//消息返回完毕，释放同步锁，具体业务需要判断指令是否匹配
                rec = 0;
                result = re;
            }

        }


    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("RemoteAddress : " + ctx.channel().remoteAddress().toString() + " active !");
        super.channelActive(ctx);
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state().equals(IdleState.READER_IDLE)) {
                // 空闲40s之后触发 (心跳包丢失)
                if (counter >= 3) {
                    // 连续丢失3个心跳包 (断开连接)
                    ctx.channel().close().sync();
                    log.error("已与" + ctx.channel().remoteAddress() + "断开连接");
                    System.out.println("已与" + ctx.channel().remoteAddress() + "断开连接");
                } else {
                    counter++;
                    log.debug(ctx.channel().remoteAddress() + "丢失了第 " + counter + " 个心跳包");
                    System.out.println("丢失了第 " + counter + " 个心跳包");
                }
            }

        }
    }


    public void resetSync(CountDownLatch latch, int rec, String cmd) {
        this.latch = latch;
        this.rec = rec;
        this.cmd = cmd;
    }

    public void setUnidId(String s) {
        this.unidId = s;
    }

    public Result getResult() {
        return result;
    }

    /***
     * 激活下次心跳
     * @param ctx
     * @param msg
     */
    public boolean heartActive(ChannelHandlerContext ctx, String msg) {
        String[] texts = msg.split("\\*");
        String key = texts[0];
        String[] datas = texts[3].split("\\,");
        boolean re = false;
        boolean needData = false;
        String len = "";
        StringBuffer command = new StringBuffer("");
        command.append("[" + key.substring(33, key.length()) + "*" + texts[1] + "*");
        String code = "";
        String cd = datas[0].replace("]", "");
        if (cd.equals("LK")) {
            code = "LK";
            re = true;
        }
        if (cd.equals("PING")) {
            code = "PING";
            Date day = new Date();
            String data = ",1";
            len = String.format("%08X", (code + data).length());
            command.append(len.substring(4, len.length()) + "*" + code + data + "]");
            needData = true;
            re = true;
        }
        if (cd.equals("KA")) {
            code = "KA";
            re = true;
        }
        if (cd.equals("CID")) {
            code = "CID";
            re = true;
        }
        if (cd.equals("DLT")) {
            code = "DLT";
            re = true;
        }
        if (cd.equals("BLE")) {
            code = "BLE";
            re = true;
        }
        if (cd.equals("LGZONE")) {  // 拿到 当前的时间
            code = "LGZONE";
            Date day = new Date();
            String time = ",+8," + sdf.format(day);
            len = String.format("%08X", (code + time).length());
            command.append(len.substring(4, len.length()) + "*" + code + time + "]");
            needData = true;
            re = true;
        }
        if (needData == false) {
            len = String.format("%08X", code.length());
            command.append(len.substring(4, len.length()) + "*" + code + "]");
        }
        if (code.length() > 0) {
            ctx.channel().writeAndFlush(command);
        }
        return re;
    }


  /*  @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        Channel channel = ctx.channel();
        if(!channel.isActive()){System.out.println("链接有断开！");}
    }*/

}
